package com.charlygao;

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.GDI32;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.RECT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.W32APIOptions;

public class Command 
{
	private final int WM_KEYDOWN = 0x100;
	private final int WM_KEYUP = 0x101;
	private final int WM_SYSKEYDOWN = 0x104;
	private final int WM_SYSKEYUP = 0x105;
	private final int WM_MOUSEMOVE = 0x200;
    private final int WM_LBUTTONDOWN = 0x201;
    private final int WM_LBUTTONUP = 0x202;
    private final int WM_LBUTTONDBLCLK = 0x203;
    private final int WM_RBUTTONDOWN = 0x204;
    private final int WM_RBUTTONUP = 0x205;
    private final int WM_RBUTTONDBLCLK = 0x206;
    
    private WPARAM wp = new WPARAM();
    private LPARAM lp = new LPARAM();
    private User32 user32;
    private Kernel32 kernel32;
    private GDI32 gdi32;
    private Robot robot;
    private DllCall dcall;
    
    public interface DllCall extends StdCallLibrary 
    {
    	int fntestdll(HWND hwnd, int x, int y);
    	
    	int readMem32(HWND hwnd, int addr);
    	
    	HANDLE getTokenAddr();
    }
    
    public Command() throws AWTException
    {
    	robot = new Robot();
    	user32 = (User32) Native.loadLibrary("User32", User32.class, W32APIOptions.UNICODE_OPTIONS);
    	kernel32 = (Kernel32) Native.loadLibrary("Kernel32", Kernel32.class, W32APIOptions.UNICODE_OPTIONS);
    	gdi32 = (GDI32) Native.loadLibrary("GDI32", GDI32.class, W32APIOptions.UNICODE_OPTIONS);
    	dcall = (DllCall) Native.loadLibrary("testdll", DllCall.class);
    }
    
    long MAKELONG(int x, int y)
    {
    	return (long)((short)x | ((int)y << 16));
    }
    
    public int getColor(HWND hwnd, int x, int y)
    {
    	// kcs fix

    	/*
    	System.out.println();
    	for (int i = -3; i <= 3; i++)
    	{
    		for (int j = -3; j <= 3; j++)
        	{
    			int ix = x - 6 + i;
    			int iy = y - 27 + j;
    			int color = dcall.fntestdll(hwnd, ix, iy);
    	    	int low = color & 0x000000FF;
    	    	int high = color & 0x00FF0000;
    	    	int tmp = color & 0xFF00FF00;
    	    	color = tmp | (high >> 16) | (low << 16);
    	    	System.out.print(Integer.toHexString(color).toUpperCase() + " ");
        	}
    		System.out.println();
    	}
    	System.out.println();*/
    	
    	int color = dcall.fntestdll(hwnd, x - 6, y - 27);
    	int low = color & 0x000000FF;
    	int high = color & 0x00FF0000;
    	int tmp = color & 0xFF00FF00;
    	color = tmp | (high >> 16) | (low << 16);
    	return color;
    }
    
    public boolean isColor(HWND hwnd, String color, int x, int y)
    {
    	//System.out.print("EXPECT: " + color.toUpperCase() + ", NOW: ");
    	//System.out.println(Integer.toHexString(getColor(hwnd, x, y)).toUpperCase());
    	return color.toUpperCase().equals(Integer.toHexString(getColor(hwnd, x, y)).toUpperCase());
    }
    
    public void PhysicalLeftClick(HWND hwnd, int i, int j)
    {
		RECT rect = new RECT();
		user32.GetWindowRect(hwnd, rect);
		user32.SetForegroundWindow(hwnd);
		robot.mouseMove(i + rect.left, j + rect.top);
		robot.mousePress(InputEvent.BUTTON1_MASK);
		robot.mouseRelease(InputEvent.BUTTON1_MASK);
    }
    
    public void LeftClick(HWND hwnd, int i, int j)
    {
    	wp.setValue(0);
    	lp.setValue(MAKELONG(i, j));
    	user32.PostMessage(hwnd, WM_LBUTTONDOWN, wp, lp);
    	user32.PostMessage(hwnd, WM_LBUTTONUP, wp, lp);
    }
    
    public void MouseMoveWithRightDown(HWND hwnd, int i, int j)
    {
    	wp.setValue(2);
    	lp.setValue(MAKELONG(i, j));
    	user32.PostMessage(hwnd, WM_MOUSEMOVE, wp, lp);
    }
    
    public void RightClick(HWND hwnd, int i, int j)
    {
    	wp.setValue(0);
    	lp.setValue(MAKELONG(i, j));
    	user32.PostMessage(hwnd, WM_RBUTTONDOWN, wp, lp);
    	user32.PostMessage(hwnd, WM_RBUTTONUP, wp, lp);
    }
    
    public void RightDown(HWND hwnd, int i, int j)
    {
    	wp.setValue(0);
    	lp.setValue(MAKELONG(i, j));
    	user32.PostMessage(hwnd, WM_RBUTTONDOWN, wp, lp);
    }
    
    public void RightUp(HWND hwnd, int i, int j)
    {
    	wp.setValue(0);
    	lp.setValue(MAKELONG(i, j));
    	user32.PostMessage(hwnd, WM_RBUTTONUP, wp, lp);
    }

    public void KeyPress(HWND hwnd, int key) throws InterruptedException
    {
    	if (key >= KeyEvent.VK_F1 && key <= KeyEvent.VK_F12)
    	{
    		wp.setValue(key);
	    	lp.setValue(1);
	    	user32.PostMessage(hwnd, WM_SYSKEYDOWN, wp, lp);
	    	user32.PostMessage(hwnd, WM_SYSKEYUP, wp, lp);
    	}
    	else if (key == KeyEvent.VK_ENTER || key == KeyEvent.VK_TAB || key == KeyEvent.VK_ESCAPE ||
    			 key == KeyEvent.VK_UP || key == KeyEvent.VK_DOWN || key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT)
    	{
    		synchronized (Command.class) 
    		{
    			user32.SetForegroundWindow(hwnd);
    			robot.keyPress(key);
    			Thread.sleep(50);
    			robot.keyRelease(key);
    		}
    	}
    	else
    	{
	    	wp.setValue(key);
	    	lp.setValue(0);
	    	user32.PostMessage(hwnd, WM_SYSKEYDOWN, wp, lp);
	    	user32.PostMessage(hwnd, WM_SYSKEYUP, wp, lp);
    	}
    }
	
    public void KeyDown(HWND hwnd, int key) throws InterruptedException
    {
    	if (key >= KeyEvent.VK_F1 && key <= KeyEvent.VK_F12)
    	{
    		wp.setValue(key);
	    	lp.setValue(1);
	    	user32.PostMessage(hwnd, WM_SYSKEYDOWN, wp, lp);
    	}
    	else if (key == KeyEvent.VK_ENTER || key == KeyEvent.VK_TAB || key == KeyEvent.VK_ESCAPE ||
    			 key == KeyEvent.VK_UP || key == KeyEvent.VK_DOWN || key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT)
    	{
    		synchronized (Command.class) 
    		{
    			Thread.sleep(100);
    			user32.SetForegroundWindow(hwnd);
    			robot.keyPress(key);
    			Thread.sleep(100);
    		}
    	}
    	else
    	{
	    	wp.setValue(key);
	    	lp.setValue(0);
	    	user32.PostMessage(hwnd, WM_SYSKEYDOWN, wp, lp);
    	}
    }
    
    public void KeyUp(HWND hwnd, int key) throws InterruptedException
    {
    	if (key >= KeyEvent.VK_F1 && key <= KeyEvent.VK_F12)
    	{
    		wp.setValue(key);
	    	lp.setValue(1);
	    	user32.PostMessage(hwnd, WM_SYSKEYUP, wp, lp);
    	}
    	else if (key == KeyEvent.VK_ENTER || key == KeyEvent.VK_TAB || key == KeyEvent.VK_ESCAPE ||
    			 key == KeyEvent.VK_UP || key == KeyEvent.VK_DOWN || key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT)
    	{
    		synchronized (Command.class) 
    		{
    			Thread.sleep(100);
    			user32.SetForegroundWindow(hwnd);
    			robot.keyRelease(key);
    			Thread.sleep(100);
    		}
    	}
    	else
    	{
	    	wp.setValue(key);
	    	lp.setValue(0);
	    	user32.PostMessage(hwnd, WM_SYSKEYUP, wp, lp);
    	}
    }
    
    /*
    // get flash.ocx base address
    public String getTokenBase(HWND hwnd)
    {
    	return "541CABEB";
    	
    	String baseAddr = "";
    	for (int i = 0x00000000; i < 0x7FFFFFFF; i += 0x10000)
    	{
    		if (dcall.readMem32(hwnd, i) == 0x905A4D && dcall.readMem32(hwnd, i + 0x138) == 0x4550)
    		{
    			baseAddr = String.format("%08X", i + 0xEC7BAB);
    			System.out.println(baseAddr);
    			break;
    		}
    	}
    	return baseAddr;
    }
    
    // get game token
    public String getToken(HWND hwnd, String addr)
    {
    	String token = "";
    	byte [] str = new byte [1];
    	int offset = Integer.parseInt(addr, 16);
    	for (int i = 0; i < 10; i++)
    	{
    		int unit = dcall.readMem32(hwnd, offset + i * 4);
    		for (int j = 0; j < 4; j++)
    		{
    			str[0] = (byte) (unit & 0xFF);
    			token += new String(str);
    			unit = unit >> 8;
    		}
    	}
    	return token;
    }*/
    
}
